const PENDING = "pending";
const FUFILLED = "fufilled";
const REJECTED = "rejected";

function runMicroTask(callback) {
  if (process && process.nextTick) {
    // node的微队列
    process.nextTick(callback);
  } else if (MutationObserver) {
    // 浏览器并支持MutationObserver
    const p = document.querySelector("p");
    // MutationObserver：观察器，内部的回调函数会被放到微队列中
    const observer = new MutationObserver(callback);
    observer.observe(p, {
      childList: true, // 观察该元素内部的变化
    });

    p.innerHTML = 1;
  } else {
    setTimeout(callback, 0);
  }
}

function isPromise(obj) {
  // 只要满足是对象，并且该对象中有then方法，那么这个对象就是promise
  return !!(obj && typeof obj === "object" && typeof obj.then === "function");
}

class MyPromise {
  constructor(executor) {
    this._status = PENDING;
    this._value = undefined;
    this._handlers = []; // 处理函数形成的队列
    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (e) {
      this._reject(e);
    }
  }

  /**
   * 向处理队列中添加一个函数
   * @param {Function} executor 添加的函数
   * @param {String} state 该函数什么状态下执行
   * @param {Function} resolve 让then函数返回的Promise成功
   * @param {Function} reject 让then函数返回的Promise失败
   */
  _pushHandlers(executor, state, resolve, reject) {
    this._handlers.push({
      executor,
      state,
      resolve,
      reject,
    });
  }

  /**
   * 根据实际情况，执行队列
   */
  _runHandlers() {
    if (this._status === PENDING) {
      // 目前任务仍在挂起
      return;
    }

    while (this._handlers[0]) {
      const handler = this._handlers[0];
      this._runOneHandler(handler);
      // 执行队列执行完成后需要将执行的任务删除
      this._handlers.shift();
    }
  }

  /**
   * 处理一个handler
   * @param {Object} handler
   */
  _runOneHandler({ executor, state, resolve, reject } = {}) {
    runMicroTask(() => {
      if (this._status !== state) {
        // 状态不一致，不处理
        return;
      }

      if (typeof executor !== "function") {
        // 传递后续处理并发一个函数
        this._status === FUFILLED ? resolve(this._value) : reject(this._value);
        return;
      }

      try {
        const result = executor(this._value);
        if (isPromise(result)) {
          // 当前队列中任务返回值未Promise，
          result.then(resolve, reject);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
      }
    });
  }

  then(onFufilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this._pushHandlers(onFufilled, FUFILLED, resolve, reject);
      this._pushHandlers(onRejected, REJECTED, resolve, reject);
      this._runHandlers(); // then函数调用需要查看当前队列中状态变化后执行队列
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(onSettled) {
    return this.then(
      (data) => {
        onSettled();
        return data;
      },
      (reason) => {
        onSettled();
        throw reason;
      }
    );
  }

  static resolve(data) {
    if (data instanceof MyPromise) {
      // data： 为Promise
      return data;
    }
    return new MyPromise((resolve, reject) => {
      // data：为Promise like
      if (isPromise(data)) {
        data.then(resolve, reject);
      } else {
        resolve(data);
      }
    });
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }

  /**
   *
   * @param {iterator} proms 数组为迭代器对象，迭代器对象只能使用forof循环，不能使用for循环，因为迭代器没有下标
   */
  static all(proms) {
    return new MyPromise((resolve, reject) => {
      try {
        const rets = [];
        let count = 0;
        let fufilledCount = 0;
        for (const p of proms) {
          let i = count;
          count++;
          MyPromise.resolve(p).then((data) => {
            fufilledCount++;
            // 按顺序添加
            rets[i] = data;
            if (count === fufilledCount) {
              // 当前是最后一个Promise完成了
              resolve(rets);
            }
          }, reject);
        }
        if (count === 0) {
          resolve(rets);
        }
      } catch (error) {
        reject(error);
      }
    });
  }

  static allSettled(proms) {
    const ps = [];
    for (const p of proms) {
      ps.push(
        MyPromise.resolve(p).then(
          (value) => ({
            status: FUFILLED,
            value,
          }),
          (reason) => ({
            status: REJECTED,
            reason,
          })
        )
      );
    }

    return MyPromise.all(ps);
  }

  static race(proms) {
    return new MyPromise((resolve, reject) => {
      for (const p of proms) {
        MyPromise.resolve(p).then(resolve, reject);
      }
    });
  }

  _changeState(newState, value) {
    // 如果当前状态不为 PENDING 就不能再次修改状态（已经修改过状态后，不让修改）
    if (this._status !== PENDING) return;
    this._status = newState;
    this._value = value;
    this._runHandlers(); // 状态变化，执行队列
  }

  _resolve(data) {
    this._changeState(FUFILLED, data);
  }

  _reject(reason) {
    this._changeState(REJECTED, reason);
  }
}

const pro = new MyPromise((resolve, reject) => {
  resolve(123);
  // reject(1223);
  // throw new Error(122);
});

pro
  .then((data) => {
    console.log(data);
    return new MyPromise((resolve) => {
      resolve(2);
    });
  })
  .then((data) => {
    console.log(data);
    return 1;
  });

// finally: 无论是什么结果，都会执行
const pro3 = pro.finally((data) => {
  // 不会接受前一个promise的执行结果,
  console.log("first", data);
});

setTimeout(() => {
  console.log("🚀 ~ pro3 ~ pro3:", pro3);
});
